package CACA;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;

import DataSetPackage.Attribute;

public class ClassifierSaver{
	
	public static CACAClassifier load(File file)
	{
		CACAClassifier c = new CACAClassifier();
		BufferedReader br;
		try {
			br = new BufferedReader(new FileReader(file));
			String line = br.readLine();
			String[] cInfoStrs = line.split(" ");
			c.noInstances = Integer.parseInt(cInfoStrs[0]);
			int n = Integer.parseInt(cInfoStrs[1]);
			c.classIndex = Integer.parseInt(cInfoStrs[2]);
			c.attributes = new ArrayList<Attribute>();
			for(int i=0;i<n;i++)
			{
				line = br.readLine();
				String strs[] = line.split(" , ");
				
				ArrayList<String> noms = new ArrayList<String>();
				for(int j = 1;j<strs.length;j++)
				{
					noms.add(strs[j]);
				}
				Attribute att = new Attribute(strs[0],noms);
				c.attributes.add(att);
			}
			c.orTree = new ORTree();
			line = br.readLine();
			int nR = Integer.parseInt(line);
			ORTreeNode[] orList = new ORTreeNode[nR];
			c.orTree.root = readNode(null,br,orList);
			for (int i = 0; i < orList.length; i++) {
				c.orTree.oRList.add(orList[i]);
			}
			br.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return c;
	}
	public static ORTreeNode readNode(ORTreeNode father,BufferedReader br,ORTreeNode[] orList) throws IOException
	{
		
		ORTreeNode node ;
		String line = br.readLine();
		String[] values = line.split(" ");
		int a = Integer.parseInt(values[0]);
		int v = Integer.parseInt(values[1]);
		int n = Integer.parseInt(values[2]);
		if(a != -1)
		{
			node = new ORTreeNode(father, new Item(a, v));
		}
		else
		{
			node = new ORTreeNode();
		}
		node.isLeaf = false;
		if(values.length > 3)
		{
			int l = Integer.parseInt(values[3]);
			int s = Integer.parseInt(values[4]);
			double c = Double.parseDouble(values[5]);
			int nI = Integer.parseInt(values[6]);
			int index = Integer.parseInt(values[7]);
			node.ruleInfor = new RuleInfo(l, s, c, nI);
			node.isLeaf = true;
			node.index = index;
			orList[index] = node;
		}
		node.childNodes = new ArrayList<ORTreeNode>();
		for(int i=0;i<n;i++)
		{
			node.childNodes.add(readNode(node,br,orList));
			
		}
		return node;
	}
	public static void save(CACAClassifier c,File file)
	{
		BufferedWriter bw;
		c.orTree.putIndex();
		try {
			bw = new BufferedWriter(new FileWriter(file));
			bw.write(String.valueOf(c.getNoInstances()));
			bw.write(' ');
			bw.write(String.valueOf(c.attributes.size()));		
			bw.write(' ');
			bw.write(String.valueOf(c.classIndex));
			for (Attribute att : c.attributes) {
				bw.write('\n');
				bw.write(att.getName());
				
				for (int i=0;i<att.getNumberOfNominal();i++) {
					bw.write(" , ");
					bw.write(att.getNominal(i));
				}
			}
			bw.write('\n');
			bw.write(String.valueOf(c.orTree.countRule()));
			writeNode(bw,c.orTree.root);
			bw.close();
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void writeNode(BufferedWriter bw,ORTreeNode node) throws IOException
	{
		bw.write('\n');
		int a = -1;
		int v = -1;
		int n = 0;
		if(node.item != null)
		{
			a = node.item.attribute;
			v = node.item.value;
		}
		if(node.childNodes != null)
		{
			n = node.childNodes.size();
		}
		bw.write(String.valueOf(a));
		bw.write(' ');
		bw.write(String.valueOf(v));
		bw.write(' ');
		bw.write(String.valueOf(n));
		if(node.isLeaf)
		{
			bw.write(' ');
			bw.write(String.valueOf(node.ruleInfor.label));
			bw.write(' ');
			bw.write(String.valueOf(node.ruleInfor.suppCount));
			bw.write(' ');
			bw.write(String.valueOf(node.ruleInfor.conf));
			bw.write(' ');
			bw.write(String.valueOf(node.ruleInfor.nItem));
			bw.write(' ');
			bw.write(String.valueOf(node.index));
		}
		for (ORTreeNode childnode : node.childNodes) {
			writeNode(bw,childnode);
		}
		
	}
	
}
